#ifndef TC_SINGLETONMGR_HH
#define TC_SINGLETONMGR_HH

/** \file SingletonMgr.hh 
 * Declarations for the class SingletonMgr.
 *
 * (c) Copyright  Semih Cemiloglu
 * All rights reserved, see COPYRIGHT file for details.
 *
 * $Id: SingletonMgr.hh 119 2006-06-21 04:57:25Z semihc $
 *
 *
 */

#include <cstddef>
#include <vector>
#include "Frame.hh"
#include "Assert.hpp"
#include "TypeInfo.hh"

namespace TC {
 

  /**
   * The structure which keeps all known information
   * about a Singleton's instance.
   */
  struct SingletonHolder
  {
    // CREATORS
    SingletonHolder()
      : m_instance(0), m_longevity(1) {}

    // Default copy ctor, copy asgnmt, dtor are fine

    // ACCESSORS
    bool operator<(const SingletonHolder& o) const
    { return m_longevity < o.m_longevity; }

    // MEMBERS
    //! We use untyped pointer to store the instance and use STL container
    void* m_instance;
    //! Type information of the instance
    TypeInfo m_type;
    //! The longevity specifier of the singleton
    unsigned m_longevity;
  };
  

  /**
   * Manager of singletons defined by the project.
   * This class itself is a singleton and should not be used 
   * to destroy itself.
   */
  class SingletonMgr
  {
  public:
    // TYPES
    typedef std::vector<SingletonHolder> SingletonCol_t;

    // CREATORS
    SingletonMgr();
    ~SingletonMgr();
    
    // MODIFIERS
    //! Get the singleton instance of a given type
    //! whose destroy callback function is given.
    //! Create the instance if it hasn't been created before.
    template <typename T>
    T* getSingleton()
    {
      T* t = 0;
      SingletonCol_t::iterator i = findSingleton(typeid(T));
      if(i != m_singletons.end()) {
        t = reinterpret_cast<T*>(i->m_instance);
      }
      else {
        SingletonHolder sh;
        sh.m_instance = t = new T;
        sh.m_type = typeid(T);
        m_singletons.push_back(sh);
      }
      return t;
    }

    //! Destroy the singleton instance of of a given type
    bool destroySingleton(TypeInfo);

    //! Get the longevity of the singleton whose type info given
    unsigned getLongevity(TypeInfo);

    //! Set the longevity of the singleton whose
    //! destroy callback is given.
    void setLongevity(TypeInfo, unsigned lgv);

    //! Destroy all singletons managed by this object
    void destroyAllSingletons();
    
  private:
    // NOT ALLOWED
    SingletonMgr(const SingletonMgr&);
    SingletonMgr& operator=(const SingletonMgr&);

    // MODIFIERS
    //! Find a position of a singleton instance whose
    //! destroy callback function is given.
    SingletonCol_t::iterator findSingleton(TypeInfo);

    //! Sort managed singletons by their longevity.
    void sortSingletonsByLongevity();

    // MEMBERS
    //! Collection of singleton holders
    SingletonCol_t m_singletons;

  }; // end class



  //! Access to the global Singleton Manager
  extern SingletonMgr* GlobalSingletonMgr();

  //! Access to the Thread-local Singleton Manager
  extern SingletonMgr* ThreadSingletonMgr();

  //! Application wide default singleton manager
  inline SingletonMgr* DefaultSingletonMgr()
  { return ThreadSingletonMgr(); }


} // end namespace




#endif /* TC_SINGLETONMGR_HH */
